<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */

namespace App\Controller;

use App\Logic\RedbillLogic;
use App\Middleware\AuthMiddleware;
use App\Model\EmailLog;
use App\Model\EmailTemplate;
use App\Model\LiveColumn;
use App\Model\LiveGift;
use App\Model\PushClientid;
use App\Model\SmsLog;
use App\Model\SmsTemplate;
use App\Model\User;
use App\Service\SettingService;
use App\Service\UploadService;
use App\Utils\Enum\ClientEnum;
use App\Utils\Enum\SceneEnum;
use Gregwar\Captcha\CaptchaBuilder;
use Hyperf\Context\Context;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\HttpServer\Annotation\Middleware;
use Hyperf\Redis\Redis;
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Psr\Http\Message\ResponseInterface;
use RedisException;
use TencentCloud\Common\Credential;
use TencentCloud\Sms\V20210111\Models\SendSmsRequest;
use TencentCloud\Sms\V20210111\SmsClient;
use function Hyperf\Support\env;

#[AutoController]
class CommonController extends AbstractController
{
    /**
     * 获取直播栏目.
     */
    public function liveColumn(): ResponseInterface
    {
        $column = LiveColumn::query()->where('enable', 1)->orderBy('listorder')->orderBy('id')->get(['id', 'title', 'image', 'sport_id']);
        return $this->apiReturn(200, 'succ', $column->toArray());
    }

    /**
     * 上报推送token.
     */
    public function reportPushClientId(): ResponseInterface
    {
        $this->parseToken();
        $userid = Context::get('userid', 0);
        if ($userid) {
            $client = $this->request->header('client', (string)ClientEnum::WEB);
            $clientId = $this->request->input('pushClientId', '');
            if (empty($clientId)) {
                PushClientid::query()->where(['userid' => $userid, 'client' => $client])->delete();
            } else {
                $log = PushClientid::query()->where(['userid' => $userid, 'client' => $client])->first();
                if ($log) {
                    PushClientid::query()->where('id', $log['id'])->update([
                        'clientid' => $clientId,
                        'last_time' => time(),
                    ]);
                } else {
                    PushClientid::create([
                        'userid' => $userid,
                        'client' => $client,
                        'clientid' => $clientId,
                        'last_time' => time(),
                    ]);
                }
            }
        }
        return $this->apiReturn();
    }

    /**
     * 清理推送ID
     * @return ResponseInterface
     */
    public function clearPushClientId(): ResponseInterface
    {
        $clientId = $this->request->input('pushClientId', '');
        if (!empty($clientId)) {
            PushClientid::query()->where('clientid', $clientId)->delete();
        }
        return $this->apiReturn();
    }

    /**
     * 获取全局配置.
     */
    public function globalConfig(): ResponseInterface
    {
        $protocol = SettingService::getGroupSetting('protocol');
        $config = [
            'wsIM' => env('IM_WEBSOCKET_URL', ''), //IM Websocket
            'regEnable' => (int)SettingService::get('reg_enable'), // 注册开关
            'sportTypes' => [ // 比赛类型
                1 => '足球',
                2 => '篮球',
            ],
            'liveColumn' => LiveColumn::query()->where('enable', 1)->orderBy('listorder', 'asc')->orderBy('id')->select(['id', 'title', 'image'])->get(), // 直播分类
            'protocol' => [
                'service' => $protocol['protocol_service'],
                'privacy' => $protocol['protocol_privacy'],
            ],
            'anchorSettled' => (int)SettingService::get('anchor_settled_enable'), //主播入驻入口
            'expertSettled' => (int)SettingService::get('expert_settled_enable'), //专家入驻入口
            'icp' => '', // ICP备案信息
            'redbillSports' => RedbillLogic::getProjectSports(),
            'redbillPlayTypes' => RedbillLogic::getProjectPlayTypes(),
            'redbillSuggestItems' => RedbillLogic::getSuggestItems(),
            'thirdOssUrl' => env('TARGET_OSS_URL').'/',
            'download' => [
                'android' => SettingService::get('android_pkg_url'),
                'ios' => SettingService::get('ios_pkg_url')
            ],
            'indexBanner' => [
                'img' => img_url(SettingService::get('ad_index_banner_1_img')),
                'link' => SettingService::get('ad_index_banner_1_link')
            ],
            'h5Url' => env('H5_URL', '')
        ];
        $config['userDefaultAvatars'] = array_filter(explode("\n", SettingService::get('user_avatars')));
        return $this->apiReturn(200, 'succ', $config);
    }

    /**
     * 发送短信验证码
     */
    public function sendSmsCode(): ResponseInterface
    {
        $param = $this->request->all();
        $sendSmsCaptcha = SettingService::get('send_sms_captcha', 0);
        if (empty($param['scene']) || empty($param['mobile']) || $sendSmsCaptcha && (empty($param['captcha_id']) || empty($param['captcha_code']))) {
            return $this->apiReturn(400, '参数错误');
        }
        if (!preg_match('/^1\d{10}$/', $param['mobile'])) {
            return $this->apiReturn(400, '手机号码格式错误');
        }

        if ($sendSmsCaptcha && !validate_captcha($param['captcha_id'], $param['captcha_code'])) {
            return $this->apiReturn(400, '图形验证码错误');
        }
        $template = SmsTemplate::query()->where('scene', $param['scene'])->first();
        if (!$template) {
            return $this->apiReturn(400, '场景不存在');
        }
        $template['params'] = new_json_decode($template['params']);

        // 上次发送间隔
        $lastSend = SmsLog::query()->where('mobile', $param['mobile'])->orderBy('id', 'DESC')->first();
        if ($lastSend && time() - $lastSend['add_time'] < 60) {
            return $this->apiReturn(400, '发送太频繁了，请稍后再试');
        }
        $todaySendTimes = SmsLog::query()->where('mobile', $param['mobile'])->whereDate('add_time', date('Y-m-d'))->count();
        if ($todaySendTimes > 10) {
            return $this->apiReturn(400, '今日发送已超过最大值');
        }

        if ($param['scene'] == SceneEnum::LOGIN && !User::query()->where('mobile', $param['mobile'])->exists()) {
            return $this->apiReturn(400, '手机号码不存在');
        }
        if ($param['scene'] == SceneEnum::REGISTER && User::query()->where('mobile', $param['mobile'])->exists()) {
            return $this->apiReturn(400, '手机号码已存在');
        }
        if ($param['scene'] == SceneEnum::BIND_MOBILE && User::query()->where('mobile', $param['mobile'])->exists()) {
            return $this->apiReturn(400, '手机号码已被其他账号绑定');
        }

        $code = random(6);
        $content = str_replace('{code}', $code, $template['content']);

        $cred = new Credential(env('SMS_SECRET_ID'), env('SMS_SECRET_KEY'));

        // 实例化要请求产品的client对象,clientProfile是可选的
        $client = new SmsClient($cred, env('SMS_REGION'));

        // 实例化一个请求对象,每个接口都会对应一个request对象
        $req = new SendSmsRequest();
        $req->fromJsonString(json_encode([
            'PhoneNumberSet' => [$param['mobile']],
            'SmsSdkAppId' => env('SMS_APPID'),
            'SignName' => env('SMS_SIGN_NAME'),
            'TemplateId' => $template['template_id'],
            'TemplateParamSet' => [$code],
        ]));

        $resp = $client->SendSms($req);
        if ($resp->SendStatusSet[0]->Code == 'Ok') {
            SmsLog::create([
                'vendor_id' => $template['vendor_id'],
                'scene' => $template['scene'],
                'userid' => Context::get('userid', 0),
                'username' => Context::get('username', ''),
                'mobile' => $param['mobile'],
                'content' => $content,
                'validate_code' => $code,
                'validate_time' => 0,
                'add_time' => time(),
            ]);
            return $this->apiReturn(200, '发送成功');
        }
        $this->logger->warning('短信发送失败', (array)$resp->SendStatusSet[0]);
        $errMsg = '发送失败';
        if ($resp->SendStatusSet[0]->Code == 'LimitExceeded.PhoneNumberThirtySecondLimit') {
            $errMsg = '1分钟内发送太频繁了';
        } elseif ($resp->SendStatusSet[0]->Code == 'LimitExceeded.PhoneNumberOneHourLimit') {
            $errMsg = '1小时内发送次数超限';
        } elseif ($resp->SendStatusSet[0]->Code == 'LimitExceeded.PhoneNumberDailyLimit') {
            $errMsg = '今日发送次数超过限制';
        }
        return $this->apiReturn(400, $errMsg);
    }

    /**
     * 发送邮件验证码
     * @return ResponseInterface
     */
    public function sendEmailCode()
    {
        $param = $this->request->all();
        $sendEmailCaptcha = SettingService::get('send_email_captcha', 0);
        if (empty($param['scene']) || empty($param['email']) || $sendEmailCaptcha && (empty($param['captcha_id']) || empty($param['captcha_code']))) {
            return $this->apiReturn(400, '参数错误');
        }
        if (!filter_var($param['email'], FILTER_VALIDATE_EMAIL)) {
            return $this->apiReturn(400, '邮件格式错误');
        }
        if ($sendEmailCaptcha && !validate_captcha($param['captcha_id'], $param['captcha_code'])) {
            return $this->apiReturn(400, '图形验证码错误');
        }
        $template = EmailTemplate::query()->where('scene', $param['scene'])->first();
        if (!$template) {
            return $this->apiReturn(400, '不支持该场景');
        }
        $template['params'] = new_json_decode($template['params']);

        // 上次发送间隔
        $lastSend = EmailLog::query()->where('email', $param['email'])->orderBy('id', 'DESC')->first();
        if ($lastSend && time() - $lastSend['add_time'] < 60) {
            return $this->apiReturn(400, '发送太频繁了，请稍后再试');
        }
        $todaySendTimes = EmailLog::query()->where('email', $param['email'])->whereDate('add_time', date('Y-m-d'))->count();
        if ($todaySendTimes > 10) {
            return $this->apiReturn(400, '今日发送已超过最大值');
        }

        if ($param['scene'] == SceneEnum::LOGIN && !User::query()->where('email', $param['email'])->exists()) {
            return $this->apiReturn(400, '邮箱不存在');
        }
        if ($param['scene'] == SceneEnum::REGISTER && User::query()->where('email', $param['email'])->exists()) {
            return $this->apiReturn(400, '邮箱地址已被使用');
        }
        if ($param['scene'] == SceneEnum::BIND_EMAIL && User::query()->where('email', $param['email'])->exists()) {
            return $this->apiReturn(400, '邮箱地址已被其他账号绑定');
        }

        $code = random(6);
        $content = str_replace('{code}', $code, $template['content']);

        try {
            $mail = new PHPMailer();
            $mail->CharSet = 'UTF-8';
            $mail->SMTPDebug = SMTP::DEBUG_SERVER;
            $mail->isSMTP();
            $mail->Host = env('SMTP_HOST');
            $mail->SMTPAuth = true;
            $mail->Username = env('SMTP_USERNAME');
            $mail->Password = env('SMTP_PASSWORD');
            $mail->From = env('SMTP_USERNAME');
            $mail->FromName = env('SMTP_FROM');
            $mail->SMTPSecure = 'ssl';
            $mail->Port = env('SMTP_PORT');
            $mail->Timeout = 5;
            $mail->addAddress($param['email']);
            $mail->isHTML(true);
            $mail->Subject = $template['title'];
            $mail->Body = $content;
            $mail->AltBody = '';
            $ret = $mail->send();
            if ($ret) {
                EmailLog::create([
                    'scene' => $template['scene'],
                    'userid' => Context::get('userid', 0),
                    'username' => Context::get('username', ''),
                    'email' => $param['email'],
                    'content' => $content,
                    'validate_code' => $code,
                    'validate_time' => 0,
                    'add_time' => time(),
                ]);
                return $this->apiReturn(200, '发送成功');
            }
            return $this->apiReturn(400, '发送失败');
        } catch (Exception $e) {
            $this->logger->warning('邮件发送失败:' . $e->getMessage());
            return $this->apiReturn(400, '发送失败，请稍后再试！');
        }
    }

    /**
     * 获取图形验证码信息.
     */
    public function loadCaptcha(): ResponseInterface
    {
        $captchaId = create_randomstr(16);
        try {
            $redis = $this->container->get(Redis::class);
            $code = random(4);
            $redis->setex('capt:' . $captchaId, 600, $code);
            return $this->apiReturn(200, 'succ', [
                'id' => $captchaId,
                'image' => dirname($this->request->url()) . '/captchaImg?id=' . $captchaId,
                'expire' => time() + 600,
            ]);
        } catch (ContainerExceptionInterface|NotFoundExceptionInterface|RedisException $e) {
            $this->logger->warning('loadCaptcha 异常:' . $e->getMessage());
            return $this->apiReturn(503, '系统异常，请稍后再试');
        }
    }

    /**
     * 显示图形验证码
     */
    public function captchaImg(): false|ResponseInterface
    {
        $id = $this->request->query('id', 0);
        if (!$id) {
            return false;
        }
        try {
            $redis = $this->container->get(Redis::class);
            $code = $redis->get('capt:' . $id);
            if (!$code) {
                return false;
            }
            $builder = new CaptchaBuilder($code);
            return $this->response->raw($builder->build()->get());
        } catch (ContainerExceptionInterface|NotFoundExceptionInterface|RedisException $e) {
            $this->logger->error('验证码图片创建失败:' . $e->getMessage());
            return false;
        }
    }

    /**
     * 校验图形验证码
     */
    public function checkCaptcha(): ResponseInterface
    {
        $id = $this->request->input('id', 0);
        if ($id) {
            try {
                $redis = $this->container->get(Redis::class);
                $code = $redis->get('capt:' . $id);
                if ($code === $this->request->input('code', '')) {
                    return $this->apiReturn(200, '验证成功');
                }
            } catch (ContainerExceptionInterface|NotFoundExceptionInterface|RedisException $e) {
                return $this->apiReturn(400, '验证失败:' . $e->getMessage());
            }
        }
        return $this->apiReturn(400, '验证失败');
    }

    /**
     * 上传图片
     * @return ResponseInterface
     */
    #[Middleware(AuthMiddleware::class)]
    public function uploadImage(): ResponseInterface
    {
        $userid = Context::get('userid', 0);
        $file = $this->request->file('file');
        try {
            $data = $this->container->get(UploadService::class)->image($file);
            return $this->apiReturn(200, '上传成功', $data);
        } catch (\Exception|NotFoundExceptionInterface|ContainerExceptionInterface $e) {
            return $this->apiReturn(400, '上传失败:' . $e->getMessage());
        }
    }

    /**
     * 获取默认头像列表
     * @return ResponseInterface
     */
    public function defaultAvatarList(): ResponseInterface
    {
        $images = [];
        for ($i = 1; $i <= 10; $i++) {
            $images[] = [
                'id' => $i,
                'img' => img_url('default_avatar/' . str_pad((string)$i, 3, '0', STR_PAD_LEFT) . '.jpg', 100)
            ];
        }
        return $this->apiReturn(200, 'succ', $images);
    }

    /**
     * 检查更新
     * @return ResponseInterface
     */
    public function checkUpgrade(): ResponseInterface
    {
        $input = $this->request->all();
        if (empty($input['platform']) || empty($input['versionName']) || empty($input['versionCode'])) {
            return $this->apiReturn(400, '检查升级参数错误');
        }
        $setting = SettingService::getGroupSetting('upgrade');
        if (!$setting['upgrade_enable'] || !in_array($input['platform'], ['android', 'ios']) || empty($setting[$input['platform'].'_pkg_url']) && empty($setting[$input['platform'].'_wgt_url'])) {
            return $this->apiReturn(200, 'succ', ['code' => 200, 'data' => ['updateFlag' => 0]]);
        }
        if (version_compare($input['wgtVersion'], $setting[$input['platform'].'_version_name'], '<')) {
            $data = [
                'updateFlag' => 1,
                'versionName' => $setting[$input['platform'].'_version_name'],
                'versionCode' => $setting[$input['platform'].'_version_code'],
                'updateTips' => $setting[$input['platform'].'_update_tips'],
                'forceUpdateFlag' => (int)$setting[$input['platform'].'_force_flag'],
                'wgtSilenceFlag' => 0,
                'isAppstoreUrl' => 0,
            ];
            if (!empty($setting[$input['platform'].'_wgt_url'])) {
                $data['wgtSilenceFlag'] = (int)$setting['wgt_silence_flag'];
                $data['versionUrl'] = $setting[$input['platform'].'_wgt_url'];
                $data['versionSize'] = $setting[$input['platform'].'_wgt_size'];
            } else {
                $data['versionUrl'] = $setting[$input['platform'].'_wgt_url'];
                $data['versionSize'] = $setting[$input['platform'].'_wgt_size'];
            }
            if ($input['platform'] == 'ios' && str_contains($data['versionUrl'], '//apps.apple.com/')) {
                $data['isAppstoreUrl'] = 1;
            }
            return $this->apiReturn(200, '发现新版本', ['code' => 200, 'data' => $data]);
        }
        return $this->apiReturn(200, 'succ', ['code' => 200, 'data' => ['updateFlag' => 0]]);
    }
}
